package org.maxgroundstation.groundstation.comm.service;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * A frame of service data.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class ServiceDataFrame {

	// Data members
	private int commType;
	private ByteBuffer dataBuff;
	private long timestamp;
	private String serviceID;
	private String clientID;
	private long frameLength;
	private int totalFragmentNumber;
	private int fragmentCount;
	
	/**
	 * Constructor.
	 */
	public ServiceDataFrame(int commType) {
		this.commType = commType;
		dataBuff = null;
		timestamp = 0L;
		serviceID = "";
		clientID = "";
		frameLength = 0L;
		totalFragmentNumber = 0;
		fragmentCount = 0;
	}
	
	/**
	 * Gets the communication type.
	 * @return communication type (UDP or TCP).
	 */
	public int getCommType() {
		return commType;
	}
	
	/**
	 * Gets the last data time stamp.
	 * @return time stamp.
	 */
	public long getTimestamp() {
		return timestamp;
	}
	
	/**
	 * Gets the service ID.
	 * @return the service ID.
	 */
	public String getServiceID() {
		return serviceID;
	}
	
	/**
	 * Gets the client ID.
	 * @return the client ID.
	 */
	public String getClientID() {
		return clientID;
	}
	
	/**
	 * Gets the size of the data.
	 * @return data size in bytes).
	 */
	public long getDataSize() {
		return frameLength;
	}
	
	/**
	 * Gets the data as a byte array.
	 * @return byte array.
	 */
	public byte[] getDataBytes() {
		if (dataBuff != null) return dataBuff.array();
		else return new byte[0];
	}
	
	/**
	 * Gets the data as a string.
	 * @return string.
	 */
	public String getDataString() {
		if (dataBuff != null) return new String(dataBuff.array());
		else return "";
	}
	
	/**
	 * Adds a data fragment.
	 * @param dataFrag the data fragment.
	 */
	public void addDataFragment(ServiceDataFragment dataFrag) {
		
		// Set time stamp.
		long dataFragTimestamp = dataFrag.getHeader().getTimestamp();
		if (dataFragTimestamp > timestamp) timestamp = dataFragTimestamp;
		//System.out.println("\nTimestamp: " + dataFragTimestamp);
		
		serviceID = dataFrag.getHeader().getServiceID();
		//System.out.println("Service ID: " + serviceID);
		clientID = dataFrag.getHeader().getClientID();
		//System.out.println("Client ID: " + clientID);
		frameLength = dataFrag.getHeader().getFrameLength();
		//System.out.println("frame length: " + frameLength);
		
		int fragmentSize = dataFrag.getHeader().getFragSize();
		//System.out.println("fragment size: " + fragmentSize);
		totalFragmentNumber = (int) Math.ceil((double) frameLength / (double) fragmentSize);
		//System.out.println("total fragment number: " + totalFragmentNumber);
		
		if (dataBuff == null) {
			dataBuff = ByteBuffer.allocate((int) frameLength);
			dataBuff.order(ByteOrder.LITTLE_ENDIAN);
		}
		
		int fragmentNumber = dataFrag.getHeader().getFragNumber();
		//System.out.println("fragment number: " + fragmentNumber);
		int fragIndex = fragmentSize * fragmentNumber;
		//System.out.println("fragment index: " + fragIndex);
		//System.out.println("data length: " + dataFrag.getData().length);
		
		dataBuff.position(fragIndex);
		dataBuff.put(dataFrag.getData());
		
		fragmentCount++;
	}
	
	/**
	 * Checks if the data frame has all of its data from fragments.
	 * @return true if data frame is full.
	 */
	public boolean isDataComplete() {
		return (totalFragmentNumber > 0) && (fragmentCount == totalFragmentNumber);
	}
}